/**
 * 8080a emulator by triton & ic
 *
 * Opcodes switches
 */

/* OPCODES & FLAGS macros */

#define _PARITY(b)     \
    ((!!((b)&0x80)) ^  \
    (!!((b)&0x40))  ^  \
    (!!((b)&0x20))  ^  \
    (!!((b)&0x10))  ^  \
    (!!((b)&0x08))  ^  \
    (!!((b)&0x04))  ^  \
    (!!((b)&0x02))  ^  \
    (!!((b)&0x01)))

#define PARITY(v)  \
            _PARITY(v) ? (_F|P_FLAG)  :  (_F&~P_FLAG)

#define SIGN(r)    \
            r&0x80 ? (_F|S_FLAG)  :  (_F&~S_FLAG)
// r>>7

#define ZERO(r)    \
            r==0 ? (_F|Z_FLAG)  :  (_F&~Z_FLAG)

#define AC(r)      \
            r&0xF ? (_F|AC_FLAG)  :  (_F&~AC_FLAG)

#define CARRY(r)    \
            r + r > 0xFF ? (_F|C_FLAG)  :  (_F&~C_FLAG)


#define ADDr(r)    \
            //_F |= CARRY(r) | AC(r) | ZERO(r) | SIGN(r) | PARITY(r)  \
            _F = SIGN(r); \
            _F = AC(r);   \
            break;

#define ADDp(r1, r2)     \
            _HL += _BC;  \
            break;

#define ANDc(r) _F |= (_F&(~C_FLAG)&(~AC_FLAG)) | ZERO(r) | SIGN(r) | PARITY(r)

#define ANDr(r)       \
            _A &= r;  \
            ANDc(r);  \
            break;

#define ANDm(r)                \
            _A &= MemRead(r);  \
            ANDc(r);           \
            break;

#define LDrr(r1,r2)  \
            r1=r2;   \
            break;

#define LDri(r)                  \
            r = MemRead(_PC++);  \
            break;

#define LDpi(r)                                        \
            r = (MemRead(_PC+1) << 8) | MemRead(_PC);  \
            _PC += 2;                                  \
            break;

#define LDmr(off, r)       \
        MemWrite(off, r);  \
        break;

#define PUSH(r)            \
            // todo
            break;

#define POP(r)            \
            // todo
            break;

#define INCr(r)                         \
            r++;                        \
            _F |= SIGN(r) | PARITY(r) | AC(r); \
            break;
// ^ H FLAG

#define SUBr(r)    \
            break;

#define ORr(r)    \
            break;

#define CPr(r)    \
            break;

#define XORr(r)    \
            break;

#define ADCr(r)    \
            break;

#define INCp(r)   \
            r++;  \
            break;

#define DECr(r)                         \
            r--;                        \
            _F = SIGN(r) | PARITY(r) | AC(r);

#define DECp(r)                         \
            r--;                        \
            break;


#define  _A   R->AF.reg.A
#define  _B   R->BC.reg.B
#define  _C   R->BC.reg.C
#define  _D   R->DE.reg.D
#define  _E   R->DE.reg.E
#define  _H   R->HL.reg.H
#define  _L   R->HL.reg.L
#define  _BC  R->BC.pair
#define  _DE  R->DE.pair
#define  _HL  R->HL.pair
#define  _F   R->AF.reg.F
#define  _PC  R->PC
#define  _SP  R->SP

//TODO:

/**
 * write push and pop defines
 * verify flag handling in defines
 */

case NOP: break;

case JR_NZ:
case JR_NC:
case JP_NZ:
case JP_NC:

printf("OPCODE not supported!\n");
exit(1);

case RET:
case RET_Z:
case RET_NZ:
case RET_C:
case RET_NC:
case RET_P:
case RET_M:
case RET_PE:
case RET_PO:

printf("OPCODE not supported!\n");
exit(1);

case CALL:
case CALL_Z:
case CALL_NZ:
case CALL_C:
case CALL_NC:
case CALL_M:
case CALL_P:
case CALL_PE:
case CALL_PO:

printf("OPCODE not supported!\n");
exit(1);

case ADD_A: ADDr(_A)
case ADD_B: ADDr(_B)
case ADD_C: ADDr(_C)
case ADD_D: ADDr(_D)
case ADD_E: ADDr(_E)
case ADD_H: ADDr(_H)
case ADD_L: ADDr(_L)
// ---------
case ADD_HL_BC: ADDp(_HL, _BC)
case ADD_HL_DE: ADDp(_HL, _DE)
case ADD_HL_HL: ADDp(_HL, _HL)
case ADD_HL_SP: ADDp(_HL, _SP)
case ADD_i: break;

case SUB_A: _A=0;_F=N_FLAG|Z_FLAG;break;
case SUB_B: SUBr(_B)
case SUB_C: SUBr(_C)
case SUB_D: SUBr(_D)
case SUB_E: SUBr(_E)
case SUB_H: SUBr(_H)
case SUB_L: SUBr(_L)
// ---------
case SUB_mHL: break;
case SUB_i:   break;

case OR_A: ORr(_A)
case OR_B: ORr(_B)
case OR_C: ORr(_C)
case OR_D: ORr(_D)
case OR_E: ORr(_E)
case OR_H: ORr(_H)
case OR_L: ORr(_L)
// ---------
case OR_mHL:
case OR_i:

case XOR_A: _A=0;_F=P_FLAG|Z_FLAG;break;
case XOR_B: XORr(_B)
case XOR_C: XORr(_C)
case XOR_D: XORr(_D)
case XOR_E: XORr(_E)
case XOR_H: XORr(_H)
case XOR_L: XORr(_L)
// ---------
case XOR_mHL: break;

case CP_A: CPr(_A)
case CP_B: CPr(_B)
case CP_C: CPr(_C)
case CP_D: CPr(_D)
case CP_E: CPr(_E)
case CP_H: CPr(_H)
case CP_L: CPr(_L)
// ---------
case CP_mHL: break;

case CPL: break;
case DAA: break;
case HALT: break;
case EI: break;

case AND_A: ANDr(_A)
case AND_B: ANDr(_B)
case AND_C: ANDr(_C)
case AND_D: ANDr(_D)
case AND_E: ANDr(_E)
case AND_H: ANDr(_H)
case AND_L: ANDr(_L)
// ---------
case AND_mHL: ANDm(_HL)
case AND_i:

case ADC_A: ADCr(_A)
case ADC_B: ADCr(_B)
case ADC_C: ADCr(_C)
case ADC_D: ADCr(_D)
case ADC_E: ADCr(_E)
case ADC_H: ADCr(_H)
case ADC_L: ADCr(_L)
// ---------
case ADC_mHL: break;
case ADC_i: break;


case PUSH_BC:  PUSH(_BC)
case PUSH_DE:  PUSH(_DE)

case POP_BC:  POP(_BC)
case POP_DE:  POP(_DE)

case INC_A:  INCr(_A)
case INC_B:  INCr(_B)
case INC_C:  INCr(_C)
case INC_D:  INCr(_D)
case INC_E:  INCr(_E)
case INC_H:  INCr(_H)
case INC_L:  INCr(_L)
// ---------
case INC_BC:  INCp(_BC)
case INC_DE:  INCp(_DE)
case INC_HL:  INCp(_HL)
case INC_SP:  INCp(_SP)

case DEC_A:  DECr(_A)
case DEC_B:  DECr(_B)
case DEC_C:  DECr(_C)
case DEC_D:  DECr(_D)
case DEC_E:  DECr(_E)
case DEC_H:  DECr(_H)
case DEC_L:  DECr(_L)
// ---------
case DEC_BC:  DECp(_BC)
case DEC_DE:  DECp(_DE)
case DEC_HL:  DECp(_HL)
case DEC_SP:  DECp(_SP)

case LD_A_i:  LDri(_A)
case LD_B_i:  LDri(_B)
case LD_C_i:  LDri(_C)
case LD_D_i:  LDri(_D)
case LD_E_i:  LDri(_E)
// ---------
case LD_BC_i:  LDpi(_BC)
case LD_DE_i:  LDpi(_DE)
case LD_HL_i:  LDpi(_HL)
case LD_SP_i:  LDpi(_SP)
// ---------
case LD_mBC_A:  LDmr(_BC,_A)
case LD_mDE_A:  LDmr(_DE,_A)
case LD_mHL_A:  LDmr(_HL,_A)
case LD_mHL_B:  LDmr(_HL,_B)
// ---------
case LD_A_A:  LDrr(_A,_A)
case LD_A_B:  LDrr(_A,_B)
case LD_A_C:  LDrr(_A,_C)
case LD_A_D:  LDrr(_A,_D)
case LD_A_E:  LDrr(_A,_E)
case LD_A_H:  LDrr(_A,_H)
case LD_A_L:  LDrr(_A,_L)
// ---------
case LD_B_A:  LDrr(_B,_A)
case LD_B_B:  LDrr(_B,_B)
case LD_B_C:  LDrr(_B,_C)
case LD_B_D:  LDrr(_B,_D)
case LD_B_E:  LDrr(_B,_E)
case LD_B_H:  LDrr(_B,_H)
case LD_B_L:  LDrr(_B,_L)
// ---------
case LD_C_A:  LDrr(_C,_A)
case LD_C_B:  LDrr(_C,_B)
case LD_C_C:  LDrr(_C,_C)
case LD_C_D:  LDrr(_C,_D)
case LD_C_E:  LDrr(_C,_E)
case LD_C_H:  LDrr(_C,_H)
case LD_C_L:  LDrr(_C,_L)
// ---------
case LD_D_A:  LDrr(_D,_A)
case LD_D_B:  LDrr(_D,_B)
case LD_D_C:  LDrr(_D,_C)
case LD_D_D:  LDrr(_D,_D)
case LD_D_E:  LDrr(_D,_E)
case LD_D_H:  LDrr(_D,_H)
case LD_D_L:  LDrr(_D,_L)
// ---------
case LD_E_A:  LDrr(_E,_A)
case LD_E_B:  LDrr(_E,_B)
case LD_E_C:  LDrr(_E,_C)
case LD_E_D:  LDrr(_E,_D)
case LD_E_E:  LDrr(_E,_E)
case LD_E_H:  LDrr(_E,_H)
case LD_E_L:  LDrr(_E,_L)
// ---------

#undef  _A
#undef  _B
#undef  _C
#undef  _D
#undef  _E
#undef  _H
#undef  _L
#undef  _BC
#undef  _DE
#undef  _HL
#undef  _F
#undef  _PC
#undef  _SP
